---
title: "Bind to Global JS Values"
description: "JS interop with global JS values in ReScript"
canonical: "/docs/manual/bind-to-global-js-values"
section: "JavaScript Interop"
order: 8
---

# Bind to Global JS Values

**First**, make sure the value you'd like to model doesn't already exist in our [provided API](/docs/manual/api/stdlib).

Some JS values, like `setTimeout`, live in the global scope. You can bind to them like so:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
@val external setTimeout: (unit => unit, int) => float = "setTimeout"
@val external clearTimeout: float => unit = "clearTimeout"
```

```js
// Empty output
```

</CodeTab>

(We already provide `setTimeout`, `clearTimeout` and others in the [Core API](/docs/manual/api/stdlib) module).

This binds to the JavaScript [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrworkerGlobalScope/setTimeout) methods and the corresponding `clearTimeout`. The `external`'s type annotation specifies that `setTimeout`:

- Takes a function that accepts `unit` and returns `unit` (which on the JS side turns into a function that accepts nothing and returns nothing aka `undefined`),
- and an integer that specifies the duration before calling said function,
- returns a number that is the timeout's ID. This number might be big, so we're modeling it as a float rather than the 32-bit int.

### Tips & Tricks

**The above isn't ideal**. See how `setTimeout` returns a `float` and `clearTimeout` accepts one. There's no guarantee that you're passing the float created by `setTimeout` into `clearTimeout`! For all we know, someone might pass it `Math.random()` into the latter.

We're in a language with a great type system now! Let's leverage a popular feature to solve this problem: abstract types.

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
type timerId
@val external setTimeout: (unit => unit, int) => timerId = "setTimeout"
@val external clearTimeout: timerId => unit = "clearTimeout"

let id = setTimeout(() => Console.log("hello"), 100)
clearTimeout(id)
```

```js
var id = setTimeout(function (param) {
  console.log("hello");
}, 100);

clearTimeout(id);
```

</CodeTab>

Clearly, `timerId` is a type that can only be created by `setTimeout`! Now we've guaranteed that `clearTimeout` _will_ be passed a valid ID. Whether it's a number under the hood is now a mere implementation detail.

Since `external`s are inlined, we end up with JS output as readable as hand-written JS.

## Global Modules

If you want to bind to a value inside a global module, e.g. `Math.random`, attach a `scope` to your `val` external:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
@scope("Math") @val external random: unit => float = "random"
let someNumber = random()
```

```js
var someNumber = Math.random();
```

</CodeTab>

you can bind to an arbitrarily deep object by passing a tuple to `scope`:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
@val @scope(("window", "location", "ancestorOrigins"))
external length: int = "length"
```

```js
// Empty output
```

</CodeTab>

This binds to `window.location.ancestorOrigins.length`.

## Special Global Values

Global values like `__filename` and `__DEV__` don't always exist; you can't even model them as an `option`, since the mere act of referring to them in ReScript (then compiled into JS) would trigger the usual `Uncaught ReferenceError: __filename is not defined` error in e.g. the browser environment.

For these troublesome global values, ReScript provides a special approach: `%external(a_single_identifier)`.

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
switch %external(__DEV__) {
| Some(_) => Console.log("dev mode")
| None => Console.log("production mode")
}
```

```js
var match = typeof __DEV__ === "undefined" ? undefined : __DEV__;

if (match !== undefined) {
  console.log("dev mode");
} else {
  console.log("production mode");
}
```

</CodeTab>

That first line's `typeof` check won't trigger a JS ReferenceError.

Another example:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
switch %external(__filename) {
| Some(f) => Console.log(f)
| None => Console.log("non-node environment")
};
```

```js
var match = typeof __filename === "undefined" ? undefined : __filename;

if (match !== undefined) {
  console.log(match);
} else {
  console.log("non-node environment");
}
```

</CodeTab>

{/* TODO: revamp this page. Not good. Tell to use globalThis["foo"], and look in our stdlib */}
